package com.inspur.edp.cef.designtime.api.json.element;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationKeyCollection;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.element.AssoCondition;
import com.inspur.edp.cef.designtime.api.element.AssoModelInfo;
import com.inspur.edp.cef.designtime.api.element.AssoVariable;
import com.inspur.edp.cef.designtime.api.element.ForeignKeyConstraintType;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspDeleteRuleType;
import com.inspur.edp.cef.designtime.api.exceptions.CommonEntityErrorCodeEnum;
import com.inspur.edp.cef.designtime.api.exceptions.CommonEntityException;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import com.inspur.edp.cef.designtime.api.json.SerializerUtils;

import java.util.ArrayList;

import static com.fasterxml.jackson.core.JsonToken.FIELD_NAME;

/**
 * The Json Parser Of GspAssociation
 *
 * @ClassName: GspAssociationDeserializer
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
public class GspAssociationDeserializer extends JsonDeserializer<GspAssociation> {
	CefFieldDeserializer filedDeserializer;

	public GspAssociationDeserializer(CefFieldDeserializer filedDeserializer) {
		this.filedDeserializer = filedDeserializer;
	}

//	public GspAssociationDeserializer()
//	{this.filedDeserializer=new CefFieldDeserializer();}

	@Override
	public GspAssociation deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
		return deserializeGspAssociation(jsonParser);
	}

	public GspAssociation deserializeGspAssociation(JsonParser jsonParser) {
		GspAssociation asso = CreateGspAssociation();
		asso.setAssoConditions(new ArrayList<>());
		AssoModelInfo assoModelInfo = new AssoModelInfo();
		assoModelInfo.setModelConfigId("");
		assoModelInfo.setMainObjCode("");
		asso.setAssoModelInfo(assoModelInfo);
		asso.setI18nResourceInfoPrefix("");
		asso.setKeepAssoPropertyForExpression(false);

		SerializerUtils.readStartObject(jsonParser);
		while (jsonParser.getCurrentToken() == FIELD_NAME) {
			String propName = SerializerUtils.readPropertyName(jsonParser);
			readPropertyValue(asso, propName, jsonParser);
		}
		SerializerUtils.readEndObject(jsonParser);
		if(asso.getBelongElement()!=null && (asso.getI18nResourceInfoPrefix()==null || "".equals(asso.getI18nResourceInfoPrefix()))){
			if(asso.getBelongElement().getI18nResourceInfoPrefix()!=null&&!"".equals(asso.getBelongElement().getI18nResourceInfoPrefix()))
				asso.setI18nResourceInfoPrefix(asso.getBelongElement().getI18nResourceInfoPrefix());
		}
		return asso;
	}

	private void readPropertyValue(GspAssociation asso, String propName, JsonParser jsonParser) {
		switch (propName) {
			case CefNames.ID:
				asso.setId(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.RefModelID:
				asso.setRefModelID(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.RefModelName:
				asso.setRefModelName(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.RefModelCode:
				asso.setRefModelCode(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.RefModelPkgName:
				asso.setRefModelPkgName(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.RefTableAlias:
				asso.setRefTableAlias(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.Asso_RefObjectID:
				asso.setRefObjectID(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.Asso_RefObjectCode:
				asso.setRefObjectCode(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.Asso_RefObjectName:
				asso.setRefObjectName(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.KeyCollection:
				readKeyCollection(jsonParser, asso);
				break;
			case CefNames.RefElementCollection:
				readRefElementCollection(jsonParser, asso);
				break;
			case CefNames.Where:
				asso.setWhere(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.AssoConditions:
				asso.setAssoConditions(readAssoConditions(jsonParser));
				break;
			case CefNames.AssoVariables:
				asso.setAssoVariables(readAssoVariables(jsonParser));
				break;
			case CefNames.AssSendMessage:
				asso.setAssSendMessage(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.ForeignKeyConstraintType:
				asso.setForeignKeyConstraintType(SerializerUtils.readPropertyValue_Enum(jsonParser, ForeignKeyConstraintType.class, ForeignKeyConstraintType.values()));
				break;
			case CefNames.DeleteRuleType:
				asso.setDeleteRuleType(SerializerUtils.readPropertyValue_Enum(jsonParser, GspDeleteRuleType.class, GspDeleteRuleType.values()));
				break;
			case CefNames.I18nResourceInfoPrefix:
				asso.setI18nResourceInfoPrefix(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.AssoModelInfo:
				asso.setAssoModelInfo(readAssoModelInfo(jsonParser));
				break;
			case CefNames.keepAssoPropertyForExpression:
				asso.setKeepAssoPropertyForExpression(SerializerUtils.readPropertyValue_boolean(jsonParser));
				break;
			default:
				if (!ReadExtendAssoProperty(asso, propName, jsonParser)) {
					throw CommonEntityException.createException(CommonEntityErrorCodeEnum.GSP_BEMODEL_COMMON_ENTITY_0006, "GspAssociationDeserializer", propName);
				}
		}
	}

	private void readKeyCollection(JsonParser jsonParser, GspAssociation asso) {
		GspAssociationKeyCollection collection = new GspAssociationKeyCollection();
		GspAssoKeyDeserializer der = new GspAssoKeyDeserializer();
		SerializerUtils.readArray(jsonParser, der, collection);
		asso.setKeyCollection(collection);
	}

	private void readRefElementCollection(JsonParser jsonParser, GspAssociation asso) {
		GspFieldCollection collection = new GspFieldCollection();
		SerializerUtils.readArray(jsonParser, filedDeserializer, collection);
		handleRefElementCollection(collection, asso);
		asso.setRefElementCollection(collection);
	}

	private void handleRefElementCollection(GspFieldCollection collection, GspAssociation asso) {
		for (IGspCommonField field : collection) {
			field.setParentAssociation(asso);
			// 关联带出字段应为false
			// Bug 305714: 字段非必填，关联出的字段必填，生成表单时显示关联出的字段不应该为必填
			field.setIsRequire(false);
			if(field.getI18nResourceInfoPrefix()==null||"".equals(field.getI18nResourceInfoPrefix()))
				if(asso.getI18nResourceInfoPrefix()!=null&&!"".equals(asso.getI18nResourceInfoPrefix()))
					field.setI18nResourceInfoPrefix(asso.getI18nResourceInfoPrefix()+"."+field.getLabelID());
		}
	}

	private AssoModelInfo readAssoModelInfo(JsonParser jsonParser) {
		AssoModelInfo info = new AssoModelInfo();
		if (SerializerUtils.readNullObject(jsonParser)) {
			return info;
		}
		SerializerUtils.readStartObject(jsonParser);
		while (jsonParser.getCurrentToken() == FIELD_NAME) {
			String propName = SerializerUtils.readPropertyName(jsonParser);
			readAssoModelInfoPropValue(jsonParser, propName, info);
		}
		SerializerUtils.readEndObject(jsonParser);
		return info;
	}

	private ArrayList<AssoCondition> readAssoConditions(JsonParser jsonParser) {
		ArrayList<AssoCondition> conditions = new ArrayList<AssoCondition>();
		if (SerializerUtils.readNullObject(jsonParser)) {
			return conditions;
		}
		String jsonValue = SerializerUtils.readPropertyValue_String(jsonParser);
		JavaType javaType = new ObjectMapper().getTypeFactory().constructParametricType(ArrayList.class, AssoCondition.class);
		conditions = SerializerUtils.readValue_Object(jsonValue, javaType);
		return conditions;
	}

	private ArrayList<AssoVariable> readAssoVariables(JsonParser jsonParser) {
		ArrayList<AssoVariable> variables = new ArrayList<AssoVariable>();
		if (SerializerUtils.readNullObject(jsonParser)) {
			return variables;
		}
		String jsonValue = SerializerUtils.readPropertyValue_String(jsonParser);
		JavaType javaType = new ObjectMapper().getTypeFactory().constructParametricType(ArrayList.class, AssoVariable.class);
		variables = SerializerUtils.readValue_Object(jsonValue, javaType);
		return variables;
	}

	private void readAssoModelInfoPropValue(JsonParser jsonParser, String propName, AssoModelInfo info) {
		switch (propName) {
			case CefNames.ModelConfigId:
				info.setModelConfigId(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.MainObjCode:
				info.setMainObjCode(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			default:
				throw CommonEntityException.createException(CommonEntityErrorCodeEnum.GSP_BEMODEL_COMMON_ENTITY_0006, "GspAssociationDeserializer", propName);
		}
	}

	private void readAssoCondition(JsonParser jsonParser, String propName, AssoModelInfo info) {
		switch (propName) {
			case CefNames.ModelConfigId:
				info.setModelConfigId(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CefNames.MainObjCode:
				info.setMainObjCode(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			default:
				throw CommonEntityException.createException(CommonEntityErrorCodeEnum.GSP_BEMODEL_COMMON_ENTITY_0006, "GspAssociationDeserializer", propName);
		}

	}

	protected GspAssociation CreateGspAssociation() {
		return new GspAssociation();
	}

	protected boolean ReadExtendAssoProperty(GspAssociation asso, String propName, JsonParser jsonParser) {
		return false;
	}
}
